package base

import (
	"context"
	"errors"
	"github.com/cloudwego/hertz/pkg/app"
	"github.com/cloudwego/hertz/pkg/common/hlog"
	"mall_frontend_api/biz/config"
	"mall_frontend_api/biz/consts"
	"mall_frontend_api/biz/lib/biz_error"
	"mall_frontend_api/biz/model"
	"mall_frontend_api/biz/model/common"
	"mall_frontend_api/biz/model/error_code"
	"mall_frontend_api/biz/pack"
	"mall_frontend_api/biz/util"
	"net/http"
	"strconv"
)

type Response struct {
	c          *app.RequestContext
	ctx        context.Context
	bizID      int64
	pagination *common.Pagination
	extra      interface{}
}

type SuccessResponse struct {
	Code       error_code.ErrorCode `json:"code"`
	Data       interface{}          `json:"data"`
	Pagination *common.Pagination   `json:"pagination,omitempty"`
	Extra      interface{}          `json:"extra,omitempty"`
}

type BadRequestResponse struct {
	Message string               `json:"message"`
	Code    error_code.ErrorCode `json:"code"`
}

type SuccessWithPageResponse struct {
	Data        interface{} `json:"data"`
	CurrentPage int         `json:"current_page"`
	Total       int64       `json:"total"`
}

func NewResponse(ctx context.Context, c *app.RequestContext) *Response {
	return &Response{
		c:     c,
		ctx:   ctx,
		bizID: config.Values.BizID,
	}
}

func (r *Response) GetPage() int {
	pageStr := r.c.Query("page")
	page, err := strconv.Atoi(pageStr)
	if err != nil {
		page = 1
	}
	return util.Page(page)
}

func (r *Response) GetSize() int {
	sizeStr := r.c.Query("size")
	size, err := strconv.Atoi(sizeStr)
	if err != nil {
		size = 0
	}
	return util.Size(size)
}

func (r *Response) Success(data ...interface{}) {
	var info interface{}
	if len(data) == 0 {
		info = make(map[string]interface{})
	} else {
		info = data[0]
	}
	r.c.JSON(http.StatusOK, SuccessResponse{
		Data:       info,
		Pagination: r.pagination,
		Extra:      r.extra,
		Code:       error_code.ErrorCode_Success,
	})
}

func (r *Response) SetPagination(total int64, page, size int) *Response {
	r.pagination = &common.Pagination{
		Total: total,
		Page:  int64(page),
		Size:  int64(size),
	}
	return r
}

func (r *Response) SetExtra(data interface{}) *Response {
	r.extra = data
	return r
}

func (r *Response) SuccessWithPage(data interface{}, total int64, page int) {
	if data == nil {
		data = make(map[string]interface{})
	}
	r.c.JSON(http.StatusOK, SuccessWithPageResponse{
		Data:        data,
		Total:       total,
		CurrentPage: page,
	})
}

func (r *Response) ServerError(err error) {
	errCode := error_code.ErrorCode_BadRequest
	logMsg := ""
	var e *biz_error.BizError
	if errors.As(err, &e) {
		errCode = e.GetErrorCode()
		logMsg = e.GetLogMessage()
	}
	hlog.CtxErrorf(r.ctx, "%s error code %d errorMsg %s", logMsg, errCode, err.Error())
	r.c.JSON(http.StatusOK, BadRequestResponse{Message: err.Error(), Code: errCode})
}

func (r *Response) GetUserInfo() *model.UserInfo {
	var info = &model.UserInfo{}
	i, exist := r.c.Get(consts.JWTUserInfo)
	if exist {
		return i.(*model.UserInfo)
	}

	return info
}

func (r *Response) GetUserNickname() string {
	return pack.GetUserName(r.GetUserInfo())
}

func (r *Response) GetRequestContext() *app.RequestContext {
	return r.c
}

func (r *Response) GetBizID() int64 {
	return r.bizID
}

func (r *Response) GetContext() context.Context {
	return r.ctx
}
